﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Text;

using Danser_Control.Exceptions;
using Danser_Control.Managers;
using Danser_Entity.Entities;
using Danser_Entity.Queries.Data;


namespace Danser_Control.ManagersImpl
{
    /// <summary>
    /// implements the IUserManager interface
    /// </summary>
    public class UserManagerImpl : IUserManager
    {
        #region C'tors:

        /// <summary>
        /// creates a UserManagerImpl instance
        /// </summary>
        public UserManagerImpl() { }

        #endregion

        #region Private Fields

        private IDBManager manager = new DBManager();

        #endregion

        #region IUserManager Members

        /// <see cref="Danser_Control.Managers.IUserManager.IsUserExists"/>
        public bool IsUserExists(string userID)
        {
            return (null != manager.GetSpecificUser(userID));
        }

        /// <see cref="Danser_Control.Managers.IUserManager.GetUserPermission"/>
        public PermissionLevel GetUserPermission(string userID)
        {
            User user = manager.GetSpecificUser(userID);
            if (null != user)
            {
                return user.Permission;
            }
            throw new DanserAuthorizationException(String.Format(ErrorMessages.UserNotExist, userID));
        }

        /// <see cref="Danser_Control.Managers.IUserManager.GetUsers"/>
        public IList<User> GetUsers(IList<string> userIDs)
        {
            List<User> userList = new List<User>();

            // if we need all users:
            if (null == userIDs || 0 == userIDs.Count)
            {
                // get all users (null means no condition)
                userList = manager.GetUsers(null);
            }
            // else - get specific users by ID:
            else
            {
                string filter = "";
                foreach (string userID in userIDs)
                {
                    filter += string.Format(DBConstants.USERS_ID + " = {0} " + ManagerConstants.OR_OPERATOR + "", userID);
                }
                // remove the last or 
                filter = filter.Remove(filter.Length - (2 + ManagerConstants.OR_OPERATOR.Length));

                userList = manager.GetUsers(filter);
            }
            return userList;
        }

        /// <see cref="Danser_Control.Managers.IUserManager.GetUsers(String)"/>
        public IList<User> GetUsers(String filter)
        {
            return manager.GetUsers(filter);
        }

        /// <see cref="Danser_Control.Managers.IUserManager.AddUser"/>
        public void AddUser(string userID, Danser_Entity.Entities.PermissionLevel permissionLevel)
        {
            // enrich user name from active directory:
            string userName = GetUserName(userID);
                        
            if (null == userName)
            {
                throw new DanserAuthorizationException(String.Format(ErrorMessages.UserNotExist, userID));
            }
            User user = new User(userID, userName, permissionLevel);
            manager.AddUser(user);
        }

        /// <see cref="Danser_Control.Managers.IUserManager.RemoveUser"/>
        public void RemoveUser(string userID)
        {
            manager.DeleteUser(userID);
        }

        /// <see cref="Danser_Control.Managers.IUserManager.ModifyPermission"/>
        public void ModifyPermission(string userID, Danser_Entity.Entities.PermissionLevel permissionLevel)
        {
            if (IsUserExists(userID))
            {
                manager.SetUserPermission(userID, permissionLevel);
            }
        }

        #endregion

        #region Private Methods:

        /// <summary>
        /// Gets from active directory the name according to specified userID
        /// </summary>
        /// <param name="userID">The id to get the name for</param>
        /// <returns></returns>
        private string GetUserName(string userID)
        {
            DirectorySearcher objSearch = new DirectorySearcher();
            SearchResult objResult = null;

            try
            {
                string fieldName = "displayName";
                objSearch.Filter = String.Format("(SAMAccountName={0})", userID);
                objSearch.PropertiesToLoad.Add(fieldName);
                objResult = objSearch.FindOne();
                return objResult.Properties[fieldName][0].ToString();
            }
            catch (System.Runtime.InteropServices.COMException)
            {
                return String.Empty;
            }
            catch (System.NullReferenceException)
            {
                return String.Empty;
            }
            catch (System.ArgumentOutOfRangeException)
            {
                return String.Empty;
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                if (objResult != null)
                {
                    objResult = null;
                }
                if (objSearch != null)
                {
                    objSearch.Dispose();
                    objSearch = null;
                }
            }
        }

        #endregion
    }
}
